<?php
namespace Matrix;

use Symfony\Component\HttpFoundation\ResponseHeaderBag,
	Symfony\Component\HttpFoundation\Response as FoundationResponse;

/**
 * 响应类
 *
 * 主要是包装了Symfony HttpFoundation Response类
 */
class Response
{
	/**
	 * 响应内容
	 *
	 * @var string
	 */
	public $content;
	
	/**
	 * The Symfony HttpFoundation Response instance.
	 *
	 * @var HttpFoundation\Response
	 */
	public $foundation;
	
	/**
	 * 创建一个响应实例
	 *
	 * @param	string	$content
	 * @param	integer	$status
	 * @param	array	$headers
	 * @return	void
	 */
	public function __construct($content, $status = 200, $headers = array())
	{
		$this->content = $content;
		$this->foundation = new FoundationResponse('', $status, $headers);
	}
	
	/**
	 * 创建一个响应实例
	 *
	 * @param	string	$content
	 * @param	integer	$status
	 * @param	array	$headers
	 * @return	self
	 */
	public static function make($content, $status = 200, $headers = array())
	{
		return new static($content, $status, $headers);
	}
	
	/**
	 * 创建一个响应实例包含一个视图
	 *
	 * @param	string	$view
	 * @param	array	$data
	 * @return	self
	 */
	public static function view($view, $data = array())
	{
		return new static(View::make($view, $data));
	}
	
	/**
	 * 创建一个JSON响应实例
	 *
	 * @param	array	$data
	 * @param	integer	$status
	 * @param	array	$headers
	 * @return	self
	 */
	public static function json($data, $status = 200, $headers = array())
	{
		$headers['Content-Type'] = 'application/json';
		return new static(json_encode($data), $status, $headers);
	}
	
	/**
	 * 实例一个JSON'd Eloquent models.
	 *
	 * @param	array	$data
	 * @param	integer	$status
	 * @param	array	$headers
	 * @return	self
	 */
	public static function eloquent($data, $status = 200, $headers = array())
	{
		$headers['Content-Type'] = 'application/json';
		return new static(eloquent_to_json($data), $status, $headers);
	}
	
	/**
	 * 实例化一个错误页面
	 *
	 * @param	integer	$code
	 * @param	array	$data
	 * @return	self
	 */
	public static function error($code, $data = array())
	{
		return new static(View::make('error.'.$code, $data), $code);
	}
	
	/**
	 * 实例化一个下载页面
	 *
	 * @param	string	$path
	 * @param	integer	$name
	 * @param	array	$headers
	 * @return	self
	 */
	public static function download($path, $name = null, $headers = array())
	{
		if ($name === null) {
			$name = basename($path);
		}
		$headers = array_merge(array(
			'Content-Description'       => 'File Transfer',
			'Content-Type'              => File::mime(File::extension($path)),
			'Content-Transfer-Encoding' => 'binary',
			'Expires'                   => 0,
			'Cache-Control'             => 'must-revalidate, post-check=0, pre-check=0',
			'Pragma'                    => 'public',
			'Content-Length'            => File::size($path),
		), $headers);
		$response = new static(File::get($path), 200, $headers);
		$d = $response->disposition($name);
		return $response->header('Content-Disposition', $d);
	}
	
	/**
	 * Create the proper Content-Disposition header.
	 *
	 * @param	string	$file
	 * @return	string
	 */
	public function disposition($file)
	{
		$type = ResponseHeaderBag::DISPOSITION_ATTACHMENT;
		return $this->foundation->headers->makeDisposition($type, $file);
	}
	
	/**
	 * 根据指定的值准备响应
	 *
	 * @param	mixed	$response
	 * @return	Response
	 */
	public static function prepare($response)
	{
		if (!$response instanceof Response) {
			$response = new static($response);
		}
		return $response;
	}

	/**
	 * 发送头部, 设置cookie, 发送内容到浏览器
	 *
	 * @return	void
	 */
	public function send()
	{
		$this->cookies();
		$this->foundation->prepare(Request::foundation());
		$this->foundation->send();
	}

	/**
	 * 转换响应内容, 并且返回
	 *
	 * @return	string
	 */
	public function render()
	{
		// If the content is a stringable object, we'll go ahead and call
		// to toString method so that we can get the string content of
		// the content object. Otherwise we'll just cast to string.
		if (str_object($this->content)) {
			$this->content = $this->content->__toString();
		} else {
			$this->content = (string)$this->content;
		}

		// Once we obtain the string content, we can set the content on
		// the HttpFoundation's Response instance in preparation for
		// sending it back to client browser when all is finished.
		$this->foundation->setContent($this->content);
		return $this->content;
	}

	/**
	 * Send all of the response headers to the browser.
	 *
	 * @return	void
	 */
	public function send_headers()
	{
		$this->foundation->prepare(Request::foundation());
		$this->foundation->sendHeaders();
	}

	/**
	 * 设置COOKIE
	 *
	 * @return	void
	 */
	protected function cookies()
	{
		$ref = new \ReflectionClass('Symfony\Component\HttpFoundation\Cookie');

		// All of the cookies for the response are actually stored on the
		// Cookie class until we're ready to send the response back to
		// the browser. This allows our cookies to be set easily.
		foreach (Cookie::$jar as $name => $cookie) {
			$config = array_values($cookie);
			$this->headers()->setCookie($ref->newInstanceArgs($config));
		}
	}

	/**
	 * 添加一个响应头部
	 *
	 * @param	string	$name
	 * @param	string	$value
	 * @return	Response
	 */
	public function header($name, $value)
	{
		$this->foundation->headers->set($name, $value);
		return $this;
	}

	/**
	 * 获取响应头部
	 *
	 * @return	ResponseParameterBag
	 */
	public function headers()
	{
		return $this->foundation->headers;
	}

	/**
	 * HTTP状态设置获取器
	 *
	 * @para	integer	$status
	 * @return	mixed
	 */
	public function status($status = null)
	{
		if (is_null($status)) {
			return $this->foundation->getStatusCode();
		} else {
			$this->foundation->setStatusCode($status);
			return $this;
		}
	}
}